package com.microframework.base.core.dbconfig;

import java.sql.Connection;
import java.util.List;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.activerecord.dialect.OracleDialect;
import com.jfinal.plugin.activerecord.dialect.PostgreSqlDialect;
import com.jfinal.plugin.activerecord.dialect.SqlServerDialect;
import com.jfinal.plugin.activerecord.dialect.Sqlite3Dialect;
import com.jfinal.plugin.druid.DruidPlugin;
import com.microframework.boot.datarule.model.domain.DbConfig;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 数据库配置工具类（线程安全）
 */
@Slf4j
public class DbConfigUtil {
    
    // 维护所有创建的插件实例（线程安全）
    private static final Map<String, DruidPlugin> DRUID_PLUGINS = new ConcurrentHashMap<>();
    private static final Map<String, ActiveRecordPlugin> ACTIVE_RECORD_PLUGINS = new ConcurrentHashMap<>();

    /**
     * 自动启动所有配置为启动的数据库连接
     */
    public static synchronized void autoStartup() {
        try {
            List<DbConfig> dbConfigs = DbConfig.dao.find(
                "SELECT * FROM " + DbConfig.TABLE_NAME + 
                " WHERE is_del = 0 AND startup_type = 0 "
            );

            for (DbConfig dbConfig : dbConfigs) {
                startDatabase(dbConfig);
            }
            log.info("成功启动 {} 个数据库连接", dbConfigs.size());
        } catch (Exception e) {
        	log.error("数据库连接自动启动失败", e);
            throw new RuntimeException("数据库连接初始化失败", e);
        }
    }

    /**
     * 启动单个数据库连接
     */
    private static void startDatabase(DbConfig dbConfig) {
        String configId = dbConfig.getId();
        
        // 避免重复启动
        if (ACTIVE_RECORD_PLUGINS.containsKey(configId)) {
            log.warn("数据库连接 {} 已存在，跳过初始化", configId);
            return;
        }

        DruidPlugin druidPlugin = new DruidPlugin(
            dbConfig.getUrl(), 
            dbConfig.getUsername(), 
            dbConfig.getPassword()
        );

        // 非SQLite数据库配置连接池参数
        if (!"sqlite".equalsIgnoreCase(dbConfig.getType())) {
            druidPlugin.set(
                dbConfig.getInitialSize(), 
                dbConfig.getMinimumIdle(), 
                dbConfig.getMaximumActiveSize()
            );
            // 可选：配置连接测试等参数
            druidPlugin.setValidationQuery("SELECT 1");
            druidPlugin.setTestWhileIdle(true);
            druidPlugin.setTestOnBorrow(false);
            druidPlugin.setTestOnReturn(false);
        }

        ActiveRecordPlugin arp = new ActiveRecordPlugin(configId, druidPlugin);
        configureActiveRecord(arp, dbConfig);

        try {
            druidPlugin.start();
            arp.start();
            DRUID_PLUGINS.put(configId, druidPlugin);
            ACTIVE_RECORD_PLUGINS.put(configId, arp);
            log.info("成功启动数据库连接：{}", configId);
        } catch (Exception e) {
            druidPlugin.stop();
            arp.stop();
        	log.error("启动数据库连接失败：" + configId, e);
            stopDatabase(configId);
            //throw new RuntimeException("无法启动数据库连接: " + configId, e);
        }
    }

    /**
     * 配置ActiveRecord插件
     */
    private static void configureActiveRecord(ActiveRecordPlugin arp, DbConfig dbConfig) {
        arp.setShowSql("1".equals(dbConfig.getShowSql()));
        arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
        arp.getEngine().setToClassPathSourceFactory();

        // 根据数据库类型设置方言
        String dbType = dbConfig.getType().toLowerCase();
        switch (dbType) {
            case "oracle":
                arp.setDialect(new OracleDialect());
                break;
            case "mysql":
                arp.setDialect(new MysqlDialect());
                break;
            case "sqlserver":
                arp.setDialect(new SqlServerDialect());
                break;
            case "sqlite":
                arp.setDialect(new Sqlite3Dialect());
                break;
            case "postgresql":
                arp.setDialect(new PostgreSqlDialect());
                break;
            default:
                throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
        }
    }

    /**
     * 停止所有数据库连接
     */
    public static synchronized void stopAll() {
        ACTIVE_RECORD_PLUGINS.keySet().forEach(DbConfigUtil::stopDatabase);
        log.info("已停止所有数据库连接");
    }

    /**
     * 停止指定数据库连接
     */
    public static synchronized void stopDatabase(String configId) {
        try {
            if (ACTIVE_RECORD_PLUGINS.containsKey(configId)) {
                ACTIVE_RECORD_PLUGINS.get(configId).stop();
                ACTIVE_RECORD_PLUGINS.remove(configId);
            }
            
            if (DRUID_PLUGINS.containsKey(configId)) {
                DRUID_PLUGINS.get(configId).stop();
                DRUID_PLUGINS.remove(configId);
            }
            log.info("成功停止数据库连接：{}", configId);
        } catch (Exception e) {
        	log.error("停止数据库连接失败：" + configId, e);
        }
    }

    /**
     * 获取所有活动的数据库配置ID
     */
    public static Set<String> getActiveConfigs() {
        return Collections.unmodifiableSet(ACTIVE_RECORD_PLUGINS.keySet());
    }

    /**
     * 检查指定配置是否已激活
     */
    public static boolean isActive(String configId) {
        return ACTIVE_RECORD_PLUGINS.containsKey(configId);
    }

    /**
     * 重新加载数据库配置（先停止再启动）
     */
    public static synchronized void reload(String configId) {
        if (isActive(configId)) {
            stopDatabase(configId);
        }
        DbConfig dbConfig = DbConfig.dao.findById(configId);
        if (dbConfig != null && StrKit.equals(dbConfig.getIsDel(), "0")) {
            startDatabase(dbConfig);
        }
    }
}
